<?php
/**
 * CDbStatement class file.
 * 数据库操作基类.
 * @author Huan Song <iphper@yeah.net>
 * @version $Id: CDbStatement.php 1 2011-06-03 17:56:37Z huan.song $
 * @package system.db
 * @since 2.0
 */
class CDbStatement extends CApplication
{
	/**
     * @var PDOStatement The driver level statement object/resource.
     */
	private $_statement;
	
	/**
     * Specifies the fetchMode of column names retrieved in queries
     * Options
     * PDO::FETCH_ASSOC (default)
     * PDO::FETCH_BOTH
     * PDO::FETCH_LAZY
     * PDO::FETCH_OBJ
	 * [PDO::FETCH_COLUMN|PDO::FETCH_GROUP]
     * @var integer
     */
    private $_fetchMode = PDO::FETCH_ASSOC;
	
	/**
     * @var string 需要绑定的SQL语句.
     */
	private $_sql;
	
	/**
     * @var array 通过bindParam(), bindValue(), bindValues()添加的数组, 这数组中的数据准备绑定到PDOStatement.
     */
	private $_bindParams = array();
	
	/**
	 * @var CDbDriver 数据库链接信息.
	 */
	private $_driver;
	
	/**
	 * @var integer 用数字索引向PDOStatement绑定数据.
	 */
	const POSITIONAL = 1;
	
	/**
	 * @var integer 用:named方式向PDOStatement绑定数据.
	 */
	const NAMED = 2;
	
	/**
	 * @var integer 向PDOStatement绑定数据的方式.
	 */
	private $_supportsParameters = self::POSITIONAL;
	
	/**
	 * 构造方法.
	 * @param CDbDriver $driver 数据库链接信息.
	 */
	public function __construct(CDbDriver $driver)
	{
		$this->_driver = $driver;
	}
	
	/**
     * 返回所有的结果集.
     * <pre>
     * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $users = $CDbStatement->fetchAllBySql($sql);
	 * 结果: 
	 * $users = array(
	 * 		'iphper1' => array(
	 * 			'username' => 'iphper1',
	 * 			'email' => 'iphper1@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		'iphper2' => array(
	 * 			'username' => 'iphper2',
	 * 			'email' => 'iphper2@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		'iphper3' => array(
	 * 			'username' => 'iphper3',
	 * 			'email' => 'iphper3@yeah.net',
	 * 			'age' => 25
	 * 		)
	 * 	);
	 * $users = $CDbStatement->fetchAllBySql($sql, null, PDO::FETCH_BOTH);
	 * 结果: 
	 * $users = array(
	 * 		'iphper1' => array(
	 * 			0 => 'iphper1',
	 * 			'username' => 'iphper1',
	 * 			1 => 'iphper1@yeah.net',
	 * 			'email' => 'iphper1@yeah.net',
	 * 			2 => 25,
	 * 			'age' => 25
	 * 		),
	 * 		'iphper1' => array(
	 * 			0 => 'iphper2',
	 * 			'username' => 'iphper2',
	 * 			1 => 'iphper2@yeah.net',
	 * 			'email' => 'iphper2@yeah.net',
	 * 			2 => 25,
	 * 			'age' => 25
	 * 		),
	 * 		'iphper1' => array(
	 * 			0 => 'iphper3',
	 * 			'username' => 'iphper3',
	 * 			1 => 'iphper3@yeah.net',
	 * 			'email' => 'iphper3@yeah.net',
	 * 			2 => 25,
	 * 			'age' => 25
	 * 		)
	 * 	);
	 * 
	 * $users = $CDbStatement->fetchAllBySql($sql, null, PDO::FETCH_COLUMN);
	 * 结果: 
	 * $users = array('iphper1', 'iphper2', 'iphper3');
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer $params.
	 * @param integer $fetchMode PDO::FETCH_ASSOC(default) | PDO::FETCH_BOTH | PDO::FETCH_COLUMN ...
     * @return mixed Array, object, or scalar depending on fetch mode.
     */
 	public function fetchAllBySql($sql = null, $params = null, $fetchMode = null)
    {
    	$this->queryInternal($sql, $params);
    	if (null === $fetchMode)
    		return $this->_statement->fetchAll($this->_fetchMode);
    	
    	return $this->_statement->fetchAll($fetchMode);
    }
    
    /**
     * 以键值对形式返回所有的结果集, 键为数组的第一个元素.
     * <pre>
     * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $users = $CDbStatement->fetchKeyAssocBySql($sql);
	 * 结果: 
	 * $users = array(
	 * 		'iphper1' => array(
	 * 			'username' => 'iphper1',
	 * 			'email' => 'iphper1@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		'iphper2' => array(
	 * 			'username' => 'iphper2',
	 * 			'email' => 'iphper2@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		'iphper3' => array(
	 * 			'username' => 'iphper3',
	 * 			'email' => 'iphper3@yeah.net',
	 * 			'age' => 25
	 * 		)
	 * 	);
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer $params.
     * @return mixed Array, object, or scalar depending on fetch mode.
     */
    public function fetchKeyAssocBySql($sql = null, $params = null)
    {
    	$this->queryInternal($sql, $params);
        $rows = array();
        while ($row = $this->_statement->fetch(PDO::FETCH_ASSOC)) 
        {
            $tmp = array_values(array_slice($row, 0, 1));
            $rows[$tmp[0]] = $row;
        }
        return $rows;
    }
    
    /**
     * 以键值对形式返回所有的结果集.
     * <pre>
     * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $users = $CDbStatement->fetchAssocBySql($sql);
	 * 结果: 
	 * $users = array(
	 * 		array(
	 * 			'username' => 'iphper1',
	 * 			'email' => 'iphper1@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		array(
	 * 			'username' => 'iphper2',
	 * 			'email' => 'iphper2@yeah.net',
	 * 			'age' => 25
	 * 		),
	 * 		array(
	 * 			'username' => 'iphper3',
	 * 			'email' => 'iphper3@yeah.net',
	 * 			'age' => 25
	 * 		)
	 * 	);
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer $params.
     * @return mixed Array, object, or scalar depending on fetch mode.
     * @see fetchAllBySql
     */
    public function fetchAssocBySql($sql = null, $params = null)
    {
    	return $this->fetchAllBySql($sql, $params, PDO::FETCH_ASSOC);
    }
	
	/**
     * 返回一条结果集.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $user = $CDbStatement->fetchOneBySql($sql, null, PDO::FETCH_ASSOC);
	 * 结果: 
	 * $user = array(
	 * 		'username' => 'iphper',
	 * 		'email' => 'iphper@yeah.net',
	 * 		'age' => 25
	 * 	);
	 * 
	 * $user = $CDbStatement->fetchOneBySql($sql, null, PDO::FETCH_BOTH);
	 * 结果: 
	 * $user = array(
	 * 		0 => 'iphper',
	 * 		'username' => 'iphper',
	 * 		1 => 'iphper@yeah.net',
	 * 		'email' => 'iphper@yeah.net',
	 * 		2 => 25,
	 * 		'age' => 25
	 * 	);
	 * 
	 * $user = $CDbStatement->fetchOneBySql($sql, null, PDO::FETCH_COLUMN);
	 * 结果: 
	 * $user = 'iphper';
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer $params.
	 * @param integer $fetchMode PDO::FETCH_ASSOC(default) | PDO::FETCH_BOTH | PDO::FETCH_COLUMN ...
     * @param integer $cursor OPTIONAL Absolute, relative, or other.
     * @param integer $offset OPTIONAL Number for absolute or relative cursors.
     * @return mixed array, object, or scalar depending on fetch mode.
     */
    public function fetchOneBySql($sql = null, $params = null, $fetchMode = null, $cursor = null, $offset = null)
    {
    	$this->queryInternal($sql, $params);
        if (null === $fetchMode) 
    		return $this->_statement->fetch($this->_fetchMode);
    	else if (null === $cursor)
    		return $this->_statement->fetch($fetchMode);
    	else if (null === $offset)
    		return $this->_statement->fetch($fetchMode, $cursor);
    	else 
    		return $this->_statement->fetch($fetchMode, $cursor, $offset);
    }
    
	/**
     * 返回一条结果集, 键值对形式.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $user = $CDbStatement->fetchAssocOneBySql($sql, null);
	 * 结果: 
	 * $user = array(
	 * 		'username' => 'iphper',
	 * 		'email' => 'iphper@yeah.net',
	 * 		'age' => 25
	 * 	);
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer $params.
     * @param integer $cursor OPTIONAL Absolute, relative, or other.
     * @param integer $offset OPTIONAL Number for absolute or relative cursors.
     * @return mixed array, object, or scalar depending on fetch mode.
     * @see fetchOneBySql
     */
    public function fetchAssocOneBySql($sql = null, $params = null, $cursor = null, $offset = null)
    {
    	return $this->fetchOneBySql($sql, $params, PDO::FETCH_ASSOC, $cursor, $offset);
    }
	
    /**
     * 返回全部结果集中指定列的结果.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users LIMIT 3';
	 * $user = $CDbStatement->fetchColumnBySql($sql, null, 2);
	 * 结果: $user = array('iphper1@yeah.net', 'iphper2@yeah.net', 'iphper3@yeah.net');
	 * </pre>
     * @param string $sql.
     * @param array|string|integer $params.
     * @param integer $columnNumber 列号.
     * @return array.
     */
    public function fetchColumnBySql($sql = null, $params = null, $columnNumber = 0)
    {
    	$this->queryInternal($sql, $params);
    	return $this->_statement->fetchAll(PDO::FETCH_COLUMN, $columnNumber);
    }
    
    /**
     * 返回一个结果集中指定列的结果.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT username, email, age FROM users WHERE username = ? LIMIT 1';
	 * $username = 'iphper';
	 * $user = $CDbStatement->fetchColumnOneBySql($sql, $username, 2);
	 * 结果: iphper@yeah.net
	 * </pre>
     * @param string $sql.
     * @param array|string|integer $params.
     * @param integer $columnNumber 列号.
     * @return string|integer.
     */
    public function fetchColumnOneBySql($sql = null, $params = null, $columnNumber = 0)
    {
    	$this->queryInternal($sql, $params);
    	return $this->_statement->fetchColumn($columnNumber);
    }
    
	/**
     * 执行数据库操作.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'INSERT INTO users (username, email, age) VALUES (?, ?, ?)';
	 * $user = array(
	 * 		'username' => 'iphper',
	 * 		'email' => 'iphper@yeah.net',
	 * 		'age' => 25
	 * 	);
	 * $CDbStatement->queryBySql($sql, $user);
	 * 
	 * $sql = 'SELECT username, email, age FROM users WHERE username = ? LIMIT 1';
	 * $username = 'iphper';
	 * $CDbStatement->queryBySql($sql, $username);
	 * </pre>
	 * @param string $sql.
	 * @param array|string|integer|null $params.
     * @return boolean 执行结果.
     * @see queryInternal
     */
    public function queryBySql($sql = null, $params = null)
    {
    	return $this->queryInternal($sql, $params);
    }
	
	/**
	 * 执行数据库操作.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'INSERT INTO users (username, email, age) VALUES (?, ?, ?)';
	 * $user = array(
	 * 		'username' => 'iphper',
	 * 		'email' => 'iphper@yeah.net',
	 * 		'age' => 25
	 * 	);
	 * $CDbStatement->queryInternal($sql, $user);
	 * 
	 * $sql = 'SELECT username, email, age FROM users WHERE username = ? LIMIT 1';
	 * $username = 'iphper';
	 * $CDbStatement->queryInternal($sql, $username);
	 * </pre>
	 * @param string|null $sql 需要执行的Sql.
	 * @param array|string|integer|null $params 需要绑定的参数.
	 * @return boolean 执行结果.
	 */
	public function queryInternal($sql = null, $params = null)
	{
		if (null !== $sql)
			$this->setSql($sql);
		
		$this->prepare();
		if (null !== $params)
		{
			if (is_array($params))
				$this->bindValues($params);
			else 
				$this->bindParam(1, $params);
		}
		
		$this->_bindParams();
		return $this->execute();
	}
	
	/**
	 * 预处理.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbStatement->prepare();
	 * </pre>
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果预处理失败, 抛出异常.
	 */
	public function prepare()
	{
		if (null === $this->_statement)
		{
			try
			{
				$this->_statement = $this->_driver->getPdo()->prepare($this->getSql());
			}
			catch(PDOException $e)
			{
				throw new CDbException('CDbStatement:prepare failed to prepare',
					array('{sql}' => $this->getSql(), '{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
			}
		}
		
		return $this;
	}
	
	/**
	 * 将预处理置空.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbStatement->cancel();
	 * </pre>
	 */
	public function cancel()
	{
		$this->_statement = null;
		$this->_bindParams = array();
	}
	
	/**
	 * 向$_bindParam数组绑定多个值. 
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $user = array(
	 * 		'username' => 'iphper',
	 * 		'email' => 'iphper@yeah.net',
	 * 		'age' => 25
	 * 	);
	 * $user = array('iphper', 'iphper@yeah.net', 25);
	 * $CDbStatement->bindValues($user);
	 * </pre>
	 * @param array $variables 需要绑定的键值对组成的数组.
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果绑定值失败, 抛出异常.
	 */
	public function bindValues(array $variables)
	{
		if ($variables)
		{
			if ($this->isPositional())
			{
				$parameter = count($this->_bindParams);
				foreach ($variables as $variable)
					$this->bindValue(++$parameter, $variable);
			}
			else 
			{
				foreach ($variables as $parameter => $variable)
					$this->bindValue($parameter, $variable);
			}
		}
		
		return $this;
	}
	
	/**
	 * 向$_bindParam数组绑定一个值(绑定值的内存地址).
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $username = 'iphper';
	 * $email = 'iphper@yeah.net';
	 * $age = 25;
	 * $CDbStatement->bindParam(1, $username, PDO::PARAM_STR)
	 * 				->bindParam(2, $email, PDO::PARAM_STR)
	 * 				->bindParam(3, $age, PDO::PARAM_INT);
	 * $CDbStatement->bindParam('username', $username, PDO::PARAM_STR)
	 * 				->bindParam('email', $email, PDO::PARAM_STR)
	 * 				->bindParam('age', $age, PDO::PARAM_INT);
	 * </pre>
	 * @param string|integer $name :列名字或键的索引.
	 * @param integer &$variable 内存地址.
	 * @param PDO::PARAM_BOOL|PDO::PARAM_INT|PDO::PARAM_STR|PDO::PARAM_NULL $dataType 需要绑定的值的类型.
	 * @param integer $length 需要绑定的数据的长度.
	 * @param null|etc. $driverOptions 其他的信息.
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果绑定值失败, 抛出异常.
	 */
	public function bindParam($parameter, &$variable, $dataType = null, $length = null, $driverOptions = null)
	{
		if (!is_int($parameter) && !is_string($parameter)) 
            throw new CDbException('CDbStatement:bindParam invalid bind-variable position', array('parameter' => $parameter));
		
	 	$position = null;
	 	if ($this->isPositional() && ($intval = (int) $parameter) > 0)
	 		$position = $intval;
	 	else if ($this->isNamed() && is_string($parameter))
	 	{
	 		if ($parameter[0] != ':')
	 			$position = ':' . $parameter;
	 		else
	 			$position = $parameter;
	 	}
		
	 	if (null === $position)
	 		throw new CDbException('CDbStatement:bindParam invalid bind-variable position', array('parameter' => $parameter));
	 	
	 	if (null === $dataType)
			$dataType = $this->_driver->getPdoType(gettype($variable));
			
		$this->_bindParams[$position] = array('variable' => $variable, 'dataType' => $dataType, 'length' => $length, 'driverOptions' => $driverOptions);
		return $this;
	}
	
	/**
	 * 向$_bindParam数组绑定一个值(数值). 
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbStatement->bindValue(1, 'iphper', PDO::PARAM_STR)
	 * 				->bindValue(2, 'iphper@yeah.net', PDO::PARAM_STR)
	 * 				->bindValue(3, '25', PDO::PARAM_INT);
	 * $CDbStatement->bindValue('username', 'iphper', PDO::PARAM_STR)
	 * 				->bindValue('email', 'iphper@yeah.net', PDO::PARAM_STR)
	 * 				->bindValue('age', '25', PDO::PARAM_INT);
	 * </pre>
	 * @param string|integer $name :列名字或键的索引.
	 * @param string|integer|.etc $variable 数值.
	 * @param PDO::PARAM_BOOL|PDO::PARAM_INT|PDO::PARAM_STR|PDO::PARAM_NULL $dataType 需要绑定的值的类型.
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果绑定值失败, 抛出异常.
	 */
	public function bindValue($parameter, $variable, $dataType = null)
	{
		return $this->bindParam($parameter, $variable, $dataType);
	}
	
	/**
	 * 向Statement对象多个值(绑定值的内存地址). 
	 * @param string|integer $name :列名字或键的索引.
	 * @param integer &$variable 内存地址.
	 * @param PDO::PARAM_BOOL|PDO::PARAM_INT|PDO::PARAM_STR|PDO::PARAM_NULL $dataType 需要绑定的值的类型.
	 * @param integer $length 需要绑定的数据的长度.
	 * @param null|etc. $driverOptions 其他的信息.
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果绑定值失败, 抛出异常.
	 */
	protected function _bindParams()
	{
		try 
        {
        	foreach ($this->_bindParams as $parameter => $variables)
        	{
				if (null === $variables['length'])
					$this->_statement->bindParam($parameter, $variables['variable'], $variables['dataType']);
				else if (null === $variables['driverOptions'])
					$this->_statement->bindParam($parameter, $variables['variable'], $variables['dataType'], $variables['length']);
				else
					$this->_statement->bindParam($parameter, $variables['variable'], $variables['dataType'], $variables['length'], $variables['driverOptions']);		
        	}
        }
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:_bindParams failed to bind param',
				array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
		return $this;
	}
	
	/**
	 * 向Statement对象绑定多个值. 
	 * @param array $values 需要绑定的键值对组成的数组.
	 * @return Object CDbStatement.
	 * @throws CDbException. 如果绑定值失败, 抛出异常.
	 */
	protected function _bindValues()
	{
		try 
        {
	        foreach ($this->_bindParams as $parameter => $variables)
				$this->_statement->bindValue($parameter, $variables['variable'], $variables['dataType']);
        }
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:_bindValues failed to bind variables',
				array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
		return $this;
	}
	
	/**
     * 执行预处理.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $params = array('username' => 'iphper', 'email' => 'iphper@yeah.net');
	 * $params = null;
	 * $bool = $CDbStatement->execute($params);
	 * </pre>
     * @param array $params OPTIONAL Values to bind to parameter placeholders.
     * @return boolean.
     */
    public function execute(array $params = null)
    {
        try 
        {
            if (null === $params) 
            	return $this->_statement->execute();
            else 
                return $this->_statement->execute($params);
        }
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:execute failed to execute',
				array('{sql}' => $this->getSql(), '{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
    }
	
	/**
     * 为statement设置默认的fetch mode.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbStatement->setFetchMode(PDO::FETCH_NUM);
	 * $CDbStatement->fetchMode = PDO::FETCH_NUM;
	 * </pre>
     * @param integer $mode The fetch mode.
     * @throws CDbException. 如果设置fetch mode失败, 抛出异常.
     */
	public function setFetchMode($fetchMode = PDO::FETCH_ASSOC)
	{
		switch ($fetchMode) 
		{
			case PDO::FETCH_NUM:
			case PDO::FETCH_ASSOC:
			case PDO::FETCH_BOTH:
			case PDO::FETCH_OBJ:
				$this->_fetchMode = $fetchMode;
				break;
			case PDO::FETCH_BOUND:
			default:
				throw new CDbException('CDbStatement:setFetchMode failed to set fetch mode',
				array('{fetchMode}' => $fetchMode));
		}
	}
	
	/**
	 * 获取受影响的行的条数.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $rowCount = $CDbStatement->getRowCount();
	 * $rowCount = $CDbStatement->rowCount;
	 * </pre>
     * @return integer 受影响的行的条数.
     * @throws CDbException. 如果影响的行的条数失败, 抛出异常.
     */
	public function getRowCount()
    {
    	try 
    	{
            return $this->_statement->rowCount();
        } 
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:getRowCount failed to get row count', 
            	array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        } 
    }
    
    /**
     * 获取当前查询的列数.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $columnCount = $CDbStatement->getColumnCount();
	 * $columnCount = $CDbStatement->columnCount;
	 * </pre>
     * @return integer 当前查询的列数.
     * @throws CDbException. 如果获取列数失败, 抛出异常.
     */
	public function getColumnCount()
    {
        try 
        {
            return $this->_statement->columnCount();
        } 
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:getColumnCount failed to get column count', 
            	array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
    }

    /**
     * 获取错误码.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $errorCode = $CDbStatement->getErrorCode();
	 * $errorCode = $CDbStatement->errorCode;
	 * </pre>
     * @return integer 错误码.
     * @throws CDbException. 如果获取错误码失败, 抛出异常.
     */
    public function getErrorCode()
    {
        try 
        {
            return $this->_statement->errorCode();
        } 
		catch (PDOException $e) 
		{
            throw new CDbException('CDbStatement:getErrorCode failed to get error code', 
            	array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
    }
	
    /**
     * 获取错误信息.
     * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $errorInfo = $CDbStatement->getErrorInfo();
	 * $errorInfo = $CDbStatement->errorInfo;
	 * </pre>
     * @return integer 错误信息.
     * @throws CDbException. 如果获取错误信息, 抛出异常.
     */
    public function getErrorInfo()
    {
        try 
        {
           return $this->_statement->errorInfo();
        } 
		catch (PDOException $e) 
		{
           throw new CDbException('CDbStatement:getErrorInfo failed to get error info', 
            	array('{errorInfo}' => $e->errorInfo, '{message}' => $e->getMessage()));
        }
    }
	
	/**
	 * 设置需要绑定的Sql.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = 'SELECT id, data, datetime FROM table';
	 * $CDbStatement->setSql($sql);
	 * $CDbStatement->sql = $sql;
	 * </pre>
	 * @param string $sql.
	 * @see getSql
	 */
	public function setSql($sql)
	{
		if (!is_string($sql))
			throw new CDbException('CDbStatement:setSql invalid sql', array('{sql}' => $sql));
		
		$this->_sql = $sql;
		$this->cancel();
		return $this;
	}
	
	/**
	 * 获取需要绑定的Sql.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $sql = $CDbStatement->getSql();
	 * $sql = $CDbStatement->sql;
	 * </pre>
	 * @return string 需要绑定的Sql.
	 * @see setSql
	 */
	public function getSql()
	{
		return $this->_sql;
	}
	
	/**
	 * 获取通过bindParam(), bindValue(), bindValues()添加的数组.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $bindParams = $CDbStatement->getBindParams();
	 * $bindParams = $CDbStatement->bindParams;
	 * </pre>
     * @return array 通过bindParam(), bindValue(), bindValues()添加的数组.
     */
	public function getBindParams()
	{
		return $this->_bindParams;
	}
	
	/**
	 * 获取向PDOStatement绑定数据的方式.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $supportsParameters = $CDbStatement->getSupportsParameters();
	 * $supportsParameters = $CDbStatement->supportsParameters;
	 * </pre>
	 * @return string 向PDOStatement绑定数据的方式.
	 * @see setSupportsParameters
	 */
	public function getSupportsParameters()
	{
		return $this->_supportsParameters;
	}
	
	/**
	 * 设置向PDOStatement绑定数据的方式.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbStatement->setSupportsParameters(CDbStatement::POSITIONAL);
	 * $CDbStatement->setSupportsParameters(CDbStatement::NAMED);
	 * $CDbStatement->supportsParameters = CDbStatement::POSITIONAL;
	 * $CDbStatement->supportsParameters = CDbStatement::NAMED;
	 * </pre>
	 * @param integer $value.
	 * @see getSupportsParameters
	 */
	public function setSupportsParameters($value = self::POSITIONAL)
	{
		if ($value === self::POSITIONAL || $value === self::NAMED)
			$this->_supportsParameters = $value;
	}
	
	/**
	 * 获取是否用数字索引向PDOStatement绑定数据.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $bool = $CDbStatement->isPositional();
	 * </pre>
	 * @return boolean 是否用数字索引向PDOStatement绑定数据.
	 * @see isNamed
	 */
	public function isPositional()
	{
		return $this->getSupportsParameters() === self::POSITIONAL;
	}
	
	/**
	 * 获取是否用:named方式向PDOStatement绑定数据.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $bool = $CDbStatement->isNamed();
	 * </pre>
	 * @return boolean 是否用:named方式向PDOStatement绑定数据.
	 * @see isPositional
	 */
	public function isNamed()
	{
		return $this->getSupportsParameters() === self::NAMED;
	}
	
	/**
	 * 获取数据库连接信息.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $CDbDriver = $CDbStatement->getDriver();
	 * $CDbDriver = $CDbStatement->driver;
	 * </pre>
	 * @return CDbDriver 数据库连接信息.
	 */
	public function getDriver()
	{
		return $this->_driver;
	}
	
	/**
	 * 获取数据库执行的信息, 测试用.
	 * <pre>
	 * $CDbDriver = new CDbDriver();
	 * $CDbStatement = new CDbStatement($CDbDriver);
	 * $log = $CDbStatement->getLog();
	 * $log = $CDbStatement->log;
	 * echo '<pre>';
	 * print_r($log);
	 * </pre>
	 * @return array sql + params 数据库执行的信息.
	 */
	public function getLog()
	{
		return array('sql' => $this->getSql(),
					 'params' => $this->_bindParams);
	}
}
